﻿#region << 文件说明 >>

/*----------------------------------------------------------------
 * 命名空间：Vampirewal.Core.Tools
 * 唯一标识：e194730c-6c3c-4cb4-b657-8cc7265d9219
 * 文件名：LoopAction
 *
 * 创建者：杨程
 * 电子邮箱：235160615@qq.com
 * 创建时间：2024/8/13 11:11:27
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/

#endregion << 文件说明 >>



namespace Vampirewal.Core;

/// <summary>
/// 循环执行方法
/// </summary>
public sealed class LoopAction : IDisposable
{
    /// <summary>
    /// 析构函数
    /// </summary>
    ~LoopAction()
    {
        this.Dispose();
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    public LoopAction(int count, TimeSpan interval, Action<LoopAction> action)
    {
        this.LoopCount = count;
        this.ExecuteAction = action;
        this.Interval = interval;
        this.WaitHandle = new AutoResetEvent(false);
    }

    /// <summary>
    /// 创建可循环操作体
    /// </summary>
    /// <param name="count">循环次数，设为-1时一直循环</param>
    /// <param name="interval">每次循环间隔</param>
    /// <param name="action">执行委托</param>
    /// <returns></returns>
    public static LoopAction CreateLoopAction(int count, TimeSpan interval, Action<LoopAction> action)
    {
        return new LoopAction(count, interval, action);
    }

    /// <summary>
    /// 创建可循环操作体
    /// </summary>
    /// <param name="count">循环次数，设为-1时一直循环</param>
    /// <param name="intervalMS">每次循环间隔，毫秒</param>
    /// <param name="action">执行委托</param>
    /// <returns></returns>
    public static LoopAction CreateLoopAction(int count, int intervalMS, Action<LoopAction> action)
    {
        return new LoopAction(count, TimeSpan.FromMilliseconds(intervalMS), action);
    }

    /// <summary>
    /// 创建可循环操作体
    /// </summary>
    /// <param name="count">循环次数，设为-1时一直循环</param>
    /// <param name="action">执行委托</param>
    /// <returns></returns>
    public static LoopAction CreateLoopAction(int count, Action<LoopAction> action)
    {
        return CreateLoopAction(count, TimeSpan.Zero, action);
    }

    /// <summary>
    /// 创建可循环操作体
    /// </summary>
    /// <param name="interval">每次循环间隔</param>
    /// <param name="action">执行委托</param>
    /// <returns></returns>
    public static LoopAction CreateLoopAction(TimeSpan interval, Action<LoopAction> action)
    {
        return CreateLoopAction(-1, interval, action);
    }

    /// <summary>
    /// 创建可循环操作体
    /// </summary>
    /// <param name="action">执行委托</param>
    /// <returns></returns>
    public static LoopAction CreateLoopAction(Action<LoopAction> action)
    {
        return CreateLoopAction(-1, TimeSpan.Zero, action);
    }

    private readonly EventWaitHandle WaitHandle;

    /// <summary>
    /// 已执行次数
    /// </summary>
    public int ExecutedCount { get; private set; }

    /// <summary>
    /// 执行间隔
    /// </summary>
    public TimeSpan Interval { get; private set; }

    /// <summary>
    /// 循环次数
    /// </summary>
    public int LoopCount { get; }

    /// <summary>
    /// 执行委托
    /// </summary>
    public Action<LoopAction> ExecuteAction { get; private set; }

    /// <summary>
    /// 运行状态
    /// </summary>
    public RunStatus RunStatus { get; private set; }

    /// <summary>
    /// 运行
    /// </summary>
    public void Run()
    {
        if (this.RunStatus == RunStatus.None)
        {
            this.RunStatus = RunStatus.Running;
            if (this.LoopCount >= 0)
            {
                for (var i = 0; i < this.LoopCount; i++)
                {
                    if (this.RunStatus == RunStatus.Disposed)
                    {
                        return;
                    }
                    this.ExecuteAction.Invoke(this);
                    this.ExecutedCount++;
                    if (this.RunStatus == RunStatus.Paused)
                    {
                        this.WaitHandle.WaitOne();
                    }
                    this.WaitHandle.WaitOne(this.Interval);
                }
            }
            else
            {
                while (true)
                {
                    if (this.RunStatus == RunStatus.Disposed)
                    {
                        return;
                    }
                    this.ExecuteAction.Invoke(this);
                    this.ExecutedCount++;
                    if (this.RunStatus == RunStatus.Paused)
                    {
                        this.WaitHandle.WaitOne();
                    }
                    this.WaitHandle.WaitOne(this.Interval);
                }
            }
            this.RunStatus = RunStatus.Completed;
        }
    }

    /// <summary>
    /// 重新运行
    /// </summary>
    public void Rerun()
    {
        if (this.RunStatus == RunStatus.Disposed)
        {
            throw new Exception("无法利用已释放的资源");
        }
        this.RunStatus = RunStatus.None;
        this.Run();
    }

    /// <summary>
    /// 以异步重新运行
    /// </summary>
    /// <returns></returns>
    public Task RerunAsync()
    {
        if (this.RunStatus == RunStatus.Disposed)
        {
            throw new Exception("无法利用已释放的资源");
        }
        this.RunStatus = RunStatus.None;
        return this.RunAsync();
    }

    /// <summary>
    /// 以异步运行
    /// </summary>
    /// <returns></returns>
    public Task RunAsync()
    {
        return Task.Run(() =>
        {
            this.Run();
        });
    }

    /// <summary>
    /// 暂停
    /// </summary>
    public void Pause()
    {
        if (this.RunStatus == RunStatus.Running)
        {
            this.WaitHandle.Reset();
            this.RunStatus = RunStatus.Paused;
        }
    }

    /// <summary>
    /// 回复
    /// </summary>
    public void Resume()
    {
        if (this.RunStatus == RunStatus.Paused)
        {
            this.RunStatus = RunStatus.Running;
            this.WaitHandle.Set();
        }
    }

    public void Dispose()
    {
        if (this.RunStatus == RunStatus.Disposed)
        {
            return;
        }
        if (this.RunStatus == RunStatus.Completed)
        {
            this.WaitHandle.Dispose();
        }
        this.RunStatus = RunStatus.Disposed;
    }
}

/// <summary>
/// 运行状态
/// </summary>
public enum RunStatus : byte
{
    /// <summary>
    /// None
    /// </summary>
    None,

    /// <summary>
    /// Running
    /// </summary>
    Running,

    /// <summary>
    /// Completed
    /// </summary>
    Completed,

    /// <summary>
    /// Pause
    /// </summary>
    Paused,

    /// <summary>
    /// Disposed
    /// </summary>
    Disposed
}